use colored::Colorize;
use futures::TryFutureExt;
use mime::Mime;
use reqwest::header::{HeaderMap, HeaderName, HeaderValue};
use reqwest::{Client, ClientBuilder, Response, header};
use std::str::FromStr;
use std::sync::OnceLock;
use std::time::Duration;

static HTTP_CLI: OnceLock<Client> = OnceLock::new();

pub fn init_http() -> anyhow::Result<()> {
    let client = cli()?;
    HTTP_CLI
        .set(client)
        .map_err(|_| anyhow::anyhow!("Failed to initialize HTTP client"))
}

fn cli() -> anyhow::Result<Client> {
    ClientBuilder::new()
        // .danger_accept_invalid_certs(true)
        // 设置连接池
        // 每个主机保持的最大空闲连接数
        .pool_max_idle_per_host(5)
        // 空闲10分钟连接失效
        .pool_idle_timeout(Duration::from_secs(600))
        // TCP 配置
        // TCP keepalive
        .tcp_keepalive(Duration::from_secs(1800))
        // 超时设置
        // 连接超时
        .connect_timeout(Duration::from_secs(10))
        // 请求超时
        .timeout(Duration::from_secs(20))
        // https相关配置；这里不是只用https协议，所以关掉
        // .https_only(false)
        .use_rustls_tls()
        .build()
        .map_err(|e| anyhow::anyhow!(e))
}

pub async fn get(url: &str, headers: Vec<String>) -> anyhow::Result<Response> {
    let client = HTTP_CLI.get().expect("http client must be initialized");

    let header_map = build_headers(headers)?;

    client
        .get(url)
        .headers(header_map)
        .send()
        .map_err(|e| anyhow::anyhow!(e))
        .await
}

pub async fn post(
    url: &str,
    headers: Vec<String>,
    body: Option<String>,
) -> anyhow::Result<Response> {
    let client = HTTP_CLI.get().expect("http client must be initialized");

    let header_map = build_headers(headers)?;

    client
        .post(url)
        .headers(header_map)
        .json(&body)
        .send()
        .map_err(|e| anyhow::anyhow!(e))
        .await
}

fn build_headers(headers: Vec<String>) -> anyhow::Result<HeaderMap> {
    let mut header_map = HeaderMap::new();
    headers.into_iter().try_for_each(|key_val| {
        if let Some((key, value)) = key_val.split_once("=") {
            let header_name = HeaderName::from_str(key)
                .map_err(|e| anyhow::anyhow!("Invalid header name '{}': {}", key, e))?;
            let header_value = HeaderValue::from_str(value)
                .map_err(|e| anyhow::anyhow!("Invalid header value '{}': {}", value, e))?;
            header_map.insert(header_name, header_value);
            Ok(())
        } else {
            return Err(anyhow::anyhow!(
                "Invalid header format: '{}'. Expected format: 'Key:Value'",
                key_val
            ));
        }
    })?;
    Ok(header_map)
}

pub async fn print_resp(response: Response) -> anyhow::Result<()> {
    print_status(&response);
    print_headers(&response);
    let mime_opt = get_content_type(&response);
    let body_str = response.text().await?;
    print_body(mime_opt, &body_str);
    Ok(())
}

/// 将服务器返回的 content-type 解析成 Mime 类型
fn get_content_type(resp: &Response) -> Option<Mime> {
    resp.headers()
        .get(header::CONTENT_TYPE)
        .and_then(|v| v.to_str().ok())
        .and_then(|v| v.parse().ok())
}

fn print_status(resp: &Response) {
    let status = format!("{:?} {}", resp.version(), resp.status()).blue();
    println!("{}\n", status);
}

fn print_headers(resp: &Response) {
    for (name, value) in resp.headers() {
        println!("{}: {:?}", name.to_string().green(), value);
    }
    print!("\n");
}

fn print_body(m: Option<Mime>, body: &str) {
    match m {
        Some(mime) => {
            if mime == mime::APPLICATION_JSON {
                println!("{}", jsonxf::pretty_print(body).unwrap().cyan())
            }
        }
        _ => println!("{body}"),
    }
}
